import math
import numpy
import random
import datetime

import common
import utils
import warningExtractor
import stormReportExtractor
import radarExtractor
import radarAnalysis
import dataStats
import vortTracker
import vortTrackProjector

def warningLabeler(warn, torReports, verbose = False):
	# max distance that a tornado report can be from the projected path to be counted
	maxTorDist = 35.0
	# time (min) to project the vort track out
	projectTime = 90
	
	vortTracks = vortTracker.vortTracker(warn)
	torMatches = {}
	reps = dataStats.matchStormWithWarning(warn, torReports)
	
	# the unmatched reps
	torMatches[-1] = []
	
	for key in vortTracks.keys():		
		if not key in torMatches.keys():
			torMatches[key] = []
		
		track = vortTracks[key]
		hdg = track.avgHdg
		spd = track.avgSpd
		initPos = utils.xyToLatLon(track.frames[0].shearFeature.center[0], track.frames[0].shearFeature.center[1])
		endPos = vortTrackProjector.projectVortTrack(initPos, hdg, spd, projectTime)
		
		for rep in reps[:]:
			pt = (rep['slat'], rep['slon'])
			d = vortTrackProjector.distFromVortTrack(pt, (initPos, endPos))
			
			if d < maxTorDist:
				torMatches[key].append(rep)
				reps.remove(rep)
				
				if verbose: 
					print 'rep added to track %d'%key
					print 'track: initPos = (%.2f, %.2f), hdg = %.2f, spd = %.2f'%(initPos[0], initPos[1], hdg, spd)
					print 'rep at time %s, start loc: (%.2f, %.2f), end loc: (%.2f, %.2f), dist = %.2f'%(str(rep['time']), 
																												rep['slat'], rep['slon'],
																												rep['elat'], rep['elon'], d)

	for rep in reps:
		print 'unmatched rep at time %s, start loc: (%.2f, %.2f), end loc: (%.2f, %.2f)'%(str(rep['time']),
																						  rep['slat'], rep['slon'],
																						  rep['elat'], rep['elon'])
		torMatches[-1].append(rep)
		
	return vortTracks, torMatches

def warningLabelerRun():
	print "-------- warningLabeler() run ----------"
	
	years = range(2005, 2010 + 1)
	
	print 'loading warnings...'
	warnings = warningExtractor.loadTorWarnings(years)

	print 'loading reports...'
	reports = stormReportExtractor.loadStormReports(years)

	timeStr = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")

	fout = open('results/%s-labels.arff'%timeStr, 'w')
	fDiagOut = open('results/%s-labels-diag.txt'%timeStr, 'w')
	fout.write('@RELATION warninglabels\n\n'\
						'@ATTRIBUTE avgHdg NUMERIC\n'\
						'@ATTRIBUTE avgRef NUMERIC\n'\
						'@ATTRIBUTE avgGrad NUMERIC\n'\
						'@ATTRIBUTE avgVelDiff NUMERIC\n'\
						'@ATTRIBUTE avgVar NUMERIC\n'\
						'@ATTRIBUTE torProduced {0,1}\n\n'\
						'@DATA\n')

	# find warnings between minDist and maxDist from the radar station
	maxDist = 80
	minDist = 5
	distValidWarnings = []
	distValidReps = []

	for warn in warnings:
		dist = utils.latLonDist(warn["countyLatLon"], common.KTLXLocation)
		if dist <= maxDist and dist >= minDist:
			distValidWarnings.append(warn)
	
	for rep in reports:
		repPos = (rep['slat'], rep['slon'])
		dist = utils.latLonDist(repPos, common.KTLXLocation)
		if dist <= maxDist and dist >= minDist:
			distValidReps.append(rep)

	dataStats.findActiveDays(distValidWarnings, distValidReps, touchdown = True, toFile = True, fileName = 'touchdown-days.txt')
	
	yearIndex = 0
	curYear = years[0]
	
	for i in range(0, len(distValidWarnings)):
		warn = distValidWarnings[i]
		numTorMatches = 0
		print 'warning for %s at %s'%(warn['countyName'], str(warn['iTime']))
		fDiagOut.write('index %d (%d): warning for %s at %s\n'%(i, yearIndex, warn['countyName'], str(warn['iTime'])))
		
		yearIndex += 1
		if warn['iTime'].year != curYear:
			curYear = warn['iTime'].year
			yearIndex = 0
		
		numVortTracks = 0
		numTorReports = 0
		numTorMatches = 0
		
		vortTracks = {}
		torMatches = {}
		try:
			vortTracks, torMatches = warningLabeler(warn, distValidReps, verbose = False)
		except Exception as inst:
			print 'warningLabeler EXCEPTION: %s'%str(inst)
			fDiagOut.write('warningLabeler EXCEPTION: %s\n'%str(inst))
		numVortTracks = len(vortTracks.keys())
		for key in torMatches.keys():
			numTorReports += len(torMatches[key])
			
		fDiagOut.write('%d vortTracks, %d tornado reports\n'%(numVortTracks, numTorReports))
		for key in torMatches.keys():
			if key == -1: continue
			
			track = vortTracks[key]
			reps = torMatches[key]
			# count total number of matched reports for this warning
			numTorMatches += len(reps)
			
			# is this track linked with a report?
			torProduced = 0
			if len(reps) > 0:
				torProduced = 1

			dataStr = '%f\t%f\t%f\t%f\t%f\t%d\n'%(track.avgHdg, track.avgRef, abs(track.avgGrad), abs(track.avgVelDiff), track.avgVar, torProduced)

			fout.write(dataStr)
			fDiagOut.write('track %d: %s'%(key, dataStr))
		fDiagOut.write('%d tornado matches\n'%numTorMatches)
		fDiagOut.write('\n')
		
		fout.flush()
		fDiagOut.flush()
		
		print '%d tracks, %d tor reports, %d tor matches'%(numVortTracks, numTorReports, numTorMatches)
		print
		
	fout.flush()
	fDiagOut.flush()
	fout.close()	
	fDiagOut.close()

def warningLabelerTest():
	print "-------- warningLabeler() test ----------"
	
	print 'loading warnings...'
	warnings = warningExtractor.loadTorWarnings([2010])

	print 'loading reports...'
	reports = stormReportExtractor.loadStormReports([2010])

	maxDist = 90
	minDist = 10
	# the warnings between 20 and 80 nm from the radar station
	distValidWarnings = []

	for warn in warnings:
		dist = utils.latLonDist(warn["countyLatLon"], common.KTLXLocation)
		if dist <= maxDist and dist >= minDist:
			distValidWarnings.append(warn)

	warningMatches = 0
	totalWarnings = 0
	
	for warn in distValidWarnings:
		stormReps = utils.matchStormWithWarning(warn, reports)
		if len(stormReps) == 0:
			continue
		
		#print 'warning for %s at %s'%(warn['countyName'], str(warn['iTime']))
		try:
			torMatches = warningLabeler(warn, reports, verbose = True)
		except:
			pass
		
		print '%d tor matches'%len(torMatches)
		if torMatches != -1:
			if len(torMatches) > 0: warningMatches += 1
			totalWarnings += 1
		print
	print 'warningMatches = %d, totalWarnings = %d'%(warningMatches, totalWarnings)
